// класс LibN1 используется для хранения библиотеки сложностей, которая для экономии хранит только функции по отрицаниям первого аргумента
class LibN1 {
private:
  Int8* lib;
  Int32 a;
  Int64 m[2];
  Int32 hm;
  Int8 sd;
  Int8 n;
  size_t sizevar;

public:
  inline Int32 fn1(Int32 f) {
    return ((f&hm) << sd) + ((f&~hm) >> sd);
  }
  
  inline Int8 comp(Int32 fi) {
    if ((fi & 1) == 0) return lib[fi >> 1] & m[0];   
    else return lib[fi >> 1] >> 4;  
  }
  
  inline Int8 get(Int32 f) {
    Int32 tf = fn1(f);
    if (tf < f) f = tf;
    Int32 N = f / a;
    Int32 spm = ((1 + N) * N) >> 1;
    size_t fi = f - spm;
    return comp(fi);
  }
  
  LibN1() {  
    m[0] = 0x0F;
    m[1] = 0xF0;  
  }
  
  size_t getSize() {
    return sizevar;
  }
  
  void init(Int8 n) {
    this->n = n;
    a = (1 << (1 << (n-1))) + 1; // 2^{2^{n-1}}+1
    sd = 1 << (n - 1);
    hm = (1 << sd) - 1;    
   
    ostringstream oss;
    oss << "binfile" << (int)n << "v_n1.mbf";
    BinFile file;
    file.open(oss.str(), BIN_FILE_READ);
    sizevar = file.getSize();
    lib = new Int8[getSize()];

    cout << "Loading LibN1 library...";
    file.readblock(lib,getSize());
    cout << "done!" << endl;
  }
  
  LibN1(Int8 n) {
    m[0] = 0xF;
    m[1] = 0xF0;
    
    init(n);       
  } 
};

